package com.ly.common.core.tool.mybatisPlus;

import com.ly.common.core.constant.BaseConstant;
import com.ly.common.core.utils.BaseUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;
import java.util.Properties;

/**
 * mybatis拦截器，自动注入创建人、创建时间、修改人、修改时间
 *
 * @Author scott
 * @Date 2019-01-19
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        String sqlId = mappedStatement.getId();
        log.debug("------sqlId------" + sqlId);
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];
        log.debug("------sqlCommandType------" + sqlCommandType);
        if (parameter == null) {
            return invocation.proceed();
        }
        boolean mapFlag = parameter instanceof Map;
        if (SqlCommandType.INSERT == sqlCommandType) {
            // 插入操作：自动填充 createTime 和 createBy
            if (mapFlag) {
                // 处理 Map 参数（如使用 @Param 注解的多参数）
                ((java.util.Map<Object, Object>) parameter).put("createTime", new Date());
                ((java.util.Map<Object, Object>) parameter).put("createBy", BaseUtils.getRealname());
            } else {
                // 处理实体类参数
                try {
                    parameter.getClass().getMethod("setCreateTime", Date.class).invoke(parameter, new Date());
                    parameter.getClass().getMethod("setCreateBy", String.class).invoke(parameter, BaseUtils.getRealname());
                } catch (Exception e) {
                    // 忽略无对应字段的实体类
                    log.debug("设置属性失败，找不到这些属性：{},{}","setCreateTime","setCreateBy");
                }
            }
            this.handleTenantId(mapFlag, parameter);
            // this.handleDelFlag(mapFlag, parameter);
        }
        if (SqlCommandType.UPDATE == sqlCommandType) {
            // 更新操作：自动填充 updateTime 和 updateBy
            if (mapFlag) {
                ((java.util.Map<Object, Object>) parameter).put("updateTime", new Date());
                ((java.util.Map<Object, Object>) parameter).put("updateBy", BaseUtils.getRealname());
            } else {
                try {
                    parameter.getClass().getMethod("setUpdateTime", Date.class).invoke(parameter, new Date());
                    parameter.getClass().getMethod("setUpdateBy", String.class).invoke(parameter, BaseUtils.getRealname());
                } catch (Exception e) {
                    // 忽略无对应字段的实体类
                }
            }
        }
        return invocation.proceed();
    }

    /**
     * 租户通用处理
     */
    private void handleTenantId(boolean mapFlag, Object parameter) throws Exception {
        if (BaseConstant.TENANT_FLAG) {
            if (mapFlag) {
                ((java.util.Map<Object, Object>) parameter).put(BaseConstant.TENANT, BaseUtils.getTenant());
            } else {

                parameter.getClass().getMethod("setTenantId", String.class).invoke(parameter, BaseUtils.getTenant());
            }
        }
    }

    /**
     * 删除状态通用处理
     */
    private void handleDelFlag(boolean mapFlag, Object parameter) throws Exception {
        if (mapFlag) {
            ((java.util.Map<Object, Object>) parameter).put("delFlag", 0);
        } else {
            //没有此属性，会报错
            parameter.getClass().getMethod("setDelFlag", Integer.class).invoke(parameter, 0);
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }
}
